package com.examples.gateway.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.examples.core.tool.constant.ExamplesConstants;
import com.examples.gateway.entity.*;
import com.examples.gateway.mapper.ExamPermissionMapper;
import com.examples.gateway.service.*;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @ClassName: ExamPermissionServiceImpl
 * @Description: TODO
 * @Author: Dai YaLu
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ExamPermissionServiceImpl extends ServiceImpl<ExamPermissionMapper, SystemPermission> implements ExamPermissionService {

    private final RedissonClient redissonClient;

    private final SystemUserRoleService userRoleService;

    private final SystemRoleService roleService;

    private final SystemRoleMenuService roleMenuService;

    private final SystemMenuService menuService;

    private final SystemMenuPermissionService menuPermissionService;

    private final static String CACHE_PREFIX = "GATEWAY:PERM";
    /**
     * 服务请求前缀
     */
    private final static String SERVER_REQ_METHOD_PREFIX = CACHE_PREFIX + "_SERVER_REQ_METHOD";
    /**
     * 服务请求路径前缀
     */
    private final static String SERVER_REQ_METHOD_PATH_PREFIX = SERVER_REQ_METHOD_PREFIX + "_PATH";

    /**
     * 租户用户前缀
     */
    private final static String USER = CACHE_PREFIX + "_USER";

    /**
     * 获取接口权限数据
     *
     * @param serviceName
     * @param reqMethod
     * @param path
     * @return
     */
    @Override
    public SystemPermission getOne(final String serviceName, final String reqMethod, final String path) {
        String key = SERVER_REQ_METHOD_PATH_PREFIX + StringPool.COLON + serviceName + StringPool.COLON + reqMethod + StringPool.COLON + path;
        RBucket<SystemPermission> bucket = redissonClient.getBucket(key);
        SystemPermission examPermission = bucket.get();
        if (ObjectUtil.isNotNull(examPermission)) {
            return examPermission;
        }
        SystemPermission permission = this.getOne(Wrappers.<SystemPermission>lambdaQuery()
                .eq(SystemPermission::getServiceName, serviceName)
                .eq(SystemPermission::getReqMethod, reqMethod)
                .eq(SystemPermission::getPath, path), false);
        if (null != permission) {
            bucket.set(permission, 24, TimeUnit.HOURS);
        }
        return permission;
    }

    /**
     * 指定服务指定请求类型下的所有权限信息
     * @param serviceName
     * @param reqMethod
     * @return
     */
    @Override
    public List<SystemPermission> getList(final String serviceName, final String reqMethod) {
        String key = SERVER_REQ_METHOD_PREFIX + StringPool.COLON + serviceName + StringPool.COLON + reqMethod;
        RBucket<List<SystemPermission>> bucket = redissonClient.getBucket(key);
        List<SystemPermission> examPermissionList = bucket.get();
        if (ObjectUtil.isNotNull(examPermissionList) && examPermissionList.size() > 0) {
            return examPermissionList;
        }
        examPermissionList = this.list(Wrappers.<SystemPermission>lambdaQuery()
                .eq(SystemPermission::getServiceName, serviceName)
                .eq(SystemPermission::getReqMethod, reqMethod));
        if (ObjectUtil.isNotNull(examPermissionList) && examPermissionList.size() > 0) {
            bucket.set(examPermissionList, 24, TimeUnit.HOURS);
        }
        return examPermissionList;
    }

    /**
     * 根据用户id和租户id获取所有的接口权限
     * @param userId
     * @return
     */
    @Override
    public List<SystemPermission> list(final Long userId) {
        String key = USER + StringPool.COLON + userId;
        RBucket<List<SystemPermission>> bucket = redissonClient.getBucket(key);
        List<SystemPermission> rList = bucket.get();
        if (CollectionUtil.isNotEmpty(rList)) {
            return rList;
        }
        // 查询用户拥有的角色
        List<Object> roleIds = userRoleService.listObjs(Wrappers.<SystemUserRole>lambdaQuery()
                .select(SystemUserRole::getRoleId)
                .eq(SystemUserRole::getUserId, userId));
        if (CollectionUtil.isEmpty(roleIds)) {
            return Lists.newArrayList();
        }
        // 过滤掉无效的角色
        List<SystemRole> roleList = roleService.list(Wrappers.<SystemRole>lambdaQuery().in(SystemRole::getId,roleIds));
        if(CollectionUtil.isEmpty(roleList)){
            return Lists.newArrayList();
        }
        List<SystemMenu> menuList = null;
        SystemRole role = roleList.stream().filter(item -> ExamplesConstants.ROLE_SUPER_ADMIN_CODE.equals(item.getCode())).findFirst().orElse(null);
        if(null != role){
            menuList = menuService.list(Wrappers.emptyWrapper());
        }else{
            List<Long> roleIdList = roleList.stream().map(SystemRole::getId).collect(Collectors.toList());
            // 查询角色对应的菜单
            List<SystemRoleMenu> roleMenuList = roleMenuService.list(Wrappers.<SystemRoleMenu>lambdaQuery().in(SystemRoleMenu::getRoleId,roleIdList));
            if(CollectionUtil.isEmpty(roleMenuList)){
                return Lists.newArrayList();
            }
            List<Long> menuIdList = roleMenuList.stream().map(SystemRoleMenu::getMenuId).collect(Collectors.toList());
            // 过滤无效的菜单
            menuList = menuService.list(Wrappers.<SystemMenu>lambdaQuery().in(SystemMenu::getId,menuIdList));
        }
        if(CollectionUtil.isEmpty(menuList)){
            return Lists.newArrayList();
        }
        // 查询菜单对应的权限
        List<SystemMenuPermission> menuPermissionList = menuPermissionService.list(Wrappers.<SystemMenuPermission>lambdaQuery().in(SystemMenuPermission::getMenuId,
                menuList.stream().map(SystemMenu::getId).collect(Collectors.toList())));
        if(CollectionUtil.isEmpty(menuPermissionList)){
            return Lists.newArrayList();
        }
        List<SystemPermission> permissionList = this.list(Wrappers.<SystemPermission>lambdaQuery().in(SystemPermission::getId,
                menuPermissionList.stream().map(SystemMenuPermission::getPermId).collect(Collectors.toList())));
        if (CollectionUtil.isNotEmpty(permissionList)) {
            bucket.set(permissionList, 24, TimeUnit.HOURS);
        }
        return permissionList;
    }
}
